using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Reflection.Metadata;
using System.Threading.Tasks;
using System.Web;
using FytSoa.Common.Utils;
using FytSoa.Domain.Core.Cache;
using Masuit.Tools.Models;
using Newtonsoft.Json;
using Quartz;

namespace FytSoa.Quartz
{
    [DisallowConcurrentExecution]
    [PersistJobDataAfterExecution]
    public class HttpJob : IJob
    {
        public async Task Execute(IJobExecutionContext context)
        {
            var maxLogCount = 20;//最多保存日志数量
            var warnTime = 20;//接口请求超过多少秒记录警告日志         
            //获取相关参数
            var requestUrl = context.JobDetail.JobDataMap.GetString(Constant.REQUESTURL);
            requestUrl = requestUrl?.IndexOf("http") == 0 ? requestUrl : "http://" + requestUrl;
            var requestParameters = context.JobDetail.JobDataMap.GetString(Constant.REQUESTPARAMETERS);
            var headersString = context.JobDetail.JobDataMap.GetString(Constant.HEADERS);
            var mailMessage = (MailMessageEnum)int.Parse(context.JobDetail.JobDataMap.GetString(Constant.MAILMESSAGE) ?? "0");
            var headers = headersString != null ? JsonConvert.DeserializeObject<Dictionary<string, string>>(headersString?.Trim()) : null;
            var requestType = (RequestTypeEnum)int.Parse(context.JobDetail.JobDataMap.GetString(Constant.REQUESTTYPE) ?? string.Empty);

            var stopwatch = new Stopwatch();
            stopwatch.Restart(); //  开始监视代码运行时间
            var response = new HttpResponseMessage();

            var logInfo = new LogInfoEntity
            {
                Url = requestUrl,
                BeginTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                RequestType = requestType.ToString(),
                Parameters = requestParameters,
                JobName = $"{context.JobDetail.Key.Group}.{context.JobDetail.Key.Name}"
            };

            var logs = context.JobDetail.JobDataMap[Constant.LOGLIST] as List<string> ?? new List<string>();
            if (logs.Count >= maxLogCount)
                logs.RemoveRange(0, logs.Count - maxLogCount);

            try
            {
                var http = HttpHelper.Instance;
                response = requestType switch
                {
                    RequestTypeEnum.Get => await http.GetAsync(requestUrl, headers),
                    RequestTypeEnum.Post => await http.PostAsync(requestUrl, requestParameters, headers),
                    RequestTypeEnum.Put => await http.PutAsync(requestUrl, requestParameters, headers),
                    RequestTypeEnum.Delete => await http.DeleteAsync(requestUrl, headers),
                    _ => response
                };
                var result = HttpUtility.HtmlEncode(await response.Content.ReadAsStringAsync());


                stopwatch.Stop(); //  停止监视            
                double seconds = stopwatch.Elapsed.TotalSeconds;  //总秒数                                
                logInfo.EndTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                logInfo.Seconds = seconds;
                logInfo.Result = $"<span class='result'>{result.PadLeft(1000)}</span>";
                if (!response.IsSuccessStatusCode)
                {
                    logInfo.ErrorMsg = $"<span class='error'>{result.PadLeft(3000)}</span>";
                    await ErrorAsync(logInfo.JobName, new Exception(result.PadLeft(3000)), JsonConvert.SerializeObject(logInfo), mailMessage);
                    context.JobDetail.JobDataMap[Constant.EXCEPTION] = JsonConvert.SerializeObject(logInfo);
                }
                else
                {
                    try
                    {
                        //这里需要和请求方约定好返回结果约定为HttpResultEntity模型
                        var httpResult = JsonConvert.DeserializeObject<HttpResultEntity>(HttpUtility.HtmlDecode(result));
                        if (httpResult is { IsSuccess: false })
                        {
                            logInfo.ErrorMsg = $"<span class='error'>{httpResult.ErrorMsg}</span>";
                            await ErrorAsync(logInfo.JobName, new Exception(httpResult.ErrorMsg), JsonConvert.SerializeObject(logInfo), mailMessage);
                            context.JobDetail.JobDataMap[Constant.EXCEPTION] = JsonConvert.SerializeObject(logInfo);
                        }
                        else
                            await InformationAsync(logInfo.JobName, JsonConvert.SerializeObject(logInfo), mailMessage);
                    }
                    catch (Exception)
                    {
                        await InformationAsync(logInfo.JobName, JsonConvert.SerializeObject(logInfo), mailMessage);
                    }
                }
            }
            catch (Exception ex)
            {
                stopwatch.Stop(); //  停止监视            
                double seconds = stopwatch.Elapsed.TotalSeconds;  //总秒数
                logInfo.ErrorMsg = $"<span class='error'>{ex.Message} {ex.StackTrace}</span>";
                context.JobDetail.JobDataMap[Constant.EXCEPTION] = JsonConvert.SerializeObject(logInfo);
                logInfo.Seconds = seconds;
                await ErrorAsync(logInfo.JobName, ex, JsonConvert.SerializeObject(logInfo), mailMessage);
            }
            finally
            {
                logs.Add($"<p>{JsonConvert.SerializeObject(logInfo)}</p>");
                context.JobDetail.JobDataMap[Constant.LOGLIST] = logs;
                double seconds = stopwatch.Elapsed.TotalSeconds;  //总秒数
                if (seconds >= warnTime)//如果请求超过20秒，记录警告日志    
                {
                    await WarningAsync(logInfo.JobName, "耗时过长 - " + JsonConvert.SerializeObject(logInfo), mailMessage);
                }
            }
        }

        private async Task WarningAsync(string title, string msg, MailMessageEnum mailMessage)
        {
            Logger.Info("Quartz警告：——"+msg);
            
            if (mailMessage == MailMessageEnum.All)
            {
                await SendMail(title,msg);
            }
        }

        private async Task InformationAsync(string title, string msg, MailMessageEnum mailMessage)
        {
            Logger.Info("Quartz信息：——"+msg);
            if (mailMessage == MailMessageEnum.All)
            {
                await SendMail(title,msg);
            }
        }

        private async Task ErrorAsync(string title, Exception ex, string msg, MailMessageEnum mailMessage)
        {
            Logger.Error(ex);
            if (mailMessage == MailMessageEnum.Err || mailMessage == MailMessageEnum.All)
            {
                await SendMail(title,msg);
            }
        }

        /// <summary>
        /// 发送邮件
        /// </summary>
        /// <param name="title"></param>
        /// <param name="msg"></param>
        private async Task SendMail(string title, string msg)
        {
            var mailConfig = RedisService.Instance.Get<MailEntity>(KeyUtils.EMAILCONFIG);
            await Task.Run(() =>
            {
                Logger.Info("发送邮件信息："+msg);
                /*new Email()
                {
                    SmtpServer = mailConfig.SmtpServer,
                    SmtpPort = mailConfig.SmtpPort, 
                    EnableSsl = mailConfig.EnableSsl,
                    Username = mailConfig.MailFrom,
                    Password = mailConfig.MailPwd,
                    Tos = mailConfig.MailTo, 
                    Subject = $"任务调度-{title}【警告】消息",
                    Body = msg,
                }.SendAsync(s =>
                {
                    Logger.Info("Quartz任务邮件发送状态："+s);
                });*/
            });
        }
    }
}